package org.apache.log4j.solon.integration;

import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.Security;

import javax.naming.NamingException;
import javax.naming.spi.NamingManager;

import org.apache.log4j.LogManager;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.xml.DOMConfigurator;
import org.noear.solon.Solon;
import org.noear.solon.Utils;
import org.noear.solon.core.AppContext;
import org.noear.solon.core.Plugin;
import org.noear.solon.core.util.LogUtil;
import org.noear.solon.core.util.ResourceUtil;
import org.noear.solon.core.util.RunUtil;


public class XPluginImp implements Plugin {

	@Override
	public void start(AppContext context) throws Throwable {
		// 禁用 JNDI
        System.setProperty("log4j.jndi.disable", "true");
        // 禁用 LDAP
        System.setProperty("log4j.ldap.disable", "true");
        // 禁用 RMI
        System.setProperty("log4j.rmi.disable", "true");
        System.setProperty("log4j.ignoreTCL", "true");
        System.setProperty("log4j2.formatMsgNoLookups", "true");
        
        initDisable();
        
		URL url = _loadPropertiesFile();
		if(url==null) {
			url = _loadXmlFile();
		}
		
		if(url == null) {
			System.err.println("Not Found log4j properties/xml file!");
			return;
		}
	}
	
	private void initDisable() {
		disableRMI();
		disableLDAPs();
		disableJNDI();
		setSecurityProperty();
	}
	
	//禁用RMI
	private void disableRMI() {
//		System.setProperty("java.rmi.server.hostname", "");
		System.setProperty("rmi.server.enable", "false");
		System.setProperty("java.rmi.server.useCodebaseOnly", "true");
		System.setProperty("java.rmi.server.disableHttp", "true");
		System.setProperty("com.sun.management.jmxremote", "false");
		System.setProperty("java.rmi.server.disableRegistry", "true");
//		if (System.getSecurityManager() == null) {
//		    System.setSecurityManager(new SecurityManager());
//		}
		String s = System.getProperty("sun.rmi.transport.tcp.maxConnections");
		if(s!=null) {
			System.setProperty("sun.rmi.transport.tcp.maxConnections","null");
		}
	}
	
	//禁用LDAP和LDAPS
	private void disableLDAPs() {
		System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false");
		System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "false");
		System.setProperty("com.sun.jndi.dns.object.trustURLCodebase", "false");
		System.setProperty("com.sun.jndi.cosnaming.object.trustURLCodebase", "false");
		System.setProperty("com.sun.jndi.ldap.connect.pool.ssl", "false");
	}
	
	//禁用JNDI
	private void disableJNDI() {
		// 设置系统属性
		System.setProperty("com.sun.jndi.ldap.object.disableEndpointChecking", "false");
		System.setProperty("com.sun.jndi.rmi.object.disableAnonymousObject", "false");
		System.setProperty("java.naming.ldap.factory.socket", "org.apache.log4j.solon.integration.NoPermissionsInitialContextFactory");
		System.setProperty("java.naming.factory.initial", "org.apache.log4j.solon.integration.NoPermissionsInitialContextFactory");
		System.setProperty("org.apache.naming.java.javaURLContext.disableUrlLoading", "true");
		System.setProperty("cxfometimes.disablejdei", "true");
		try {
			NamingManager.setInitialContextFactoryBuilder(env -> new NoPermissionsInitialContextFactory());
		} catch (NamingException e) {
			e.printStackTrace();
		}
		Security.setProperty("jndi.initial.context.factory", "org.apache.log4j.solon.integration.NoPermissionsInitialContextFactory");
	}
	
	private void setSecurityProperty() {
//		# 禁止RMI URL加载
		Security.setProperty("secureremoteobject.allowLoadCodebaseProperty", "false");
//		# 禁止从URL加载对象
		Security.setProperty("secureremoteobject.codebasePrincipalSupport", "false");
//		# 禁止使用RMI注册中心
		Security.setProperty("secureregistry.disable", "true");
	}
	
	private URL _loadXmlFile() {
		URL url=null;
		String[] xml = new String[] { "log4j.xml", "log4j-" + Solon.cfg().env() + ".xml", "log4j-file.xml","log4j-file-" + Solon.cfg().env() + ".xml"};
		for(String f:xml) {
			url = ResourceUtil.getResource(f);
			if(url!=null) {
				DOMConfigurator.configure(url);
				break;
			}
		}
		return url;
	}
	
	private URL _loadPropertiesFile() {
		URL url=null;
		String[] xml = new String[] { "log4j.properties", "log4j-" + Solon.cfg().env() + ".properties", "log4j-file.properties","log4j-file-" + Solon.cfg().env() + ".properties"};
		for(String f:xml) {
			url = ResourceUtil.getResource(f);
			if(url!=null) {
				PropertyConfigurator.configure(url);
				break;
			}
		}
		return url;
	}
	

	@Override
	public void stop() throws Throwable {
		LogManager.shutdown();
	}

	/**
	 * 基于配置，获取日志配置文件
	 */
	private URL getUrlOfConfig() throws MalformedURLException {
		String logConfig = Solon.cfg().get("logging.config");// By default, Spring Boot picks up the native
																// configuration from its default location for the
																// system (such as classpath:logback.xml for Logback),
																// but you can set the location of the config file by
		if (Utils.isNotEmpty(logConfig)) {
			File logConfigFile = new File(logConfig);
			if (logConfigFile.exists()) {
				return logConfigFile.toURI().toURL();
			} else {
				// 改成异步，不然 LogUtil.global() 初始化未完成
				RunUtil.async(() -> {
					LogUtil.global().warn("Props: No log config file: " + logConfig);
				});
			}
		}

		return null;
	}

}
